<?php

namespace plugin\webman\gateway;

use app\model\Base;
use App\Model\Logic\MonitorLogic;
use GatewayWorker\Lib\Gateway;
use Illuminate\Support\Env;
use support\Cache;
use support\Redis;

/**
 * Class Events
 * @package plugin\webman\gateway
 *子进程 频繁 重启
 * 日志位置
 *  /www/first/webmanlds/runtime/logs
 */

/// 机器人给远控打不通

//机器人没有连接 不需要挂断
class Events
{

    const ROLE_ROBOT = "robot_coach";
    const ROLE_sub3robot = "sub3robot";
    //call_status
    const SUR_FREE = 0; //有空
    const SUR_USE = 1; // 占线
    const SUR_B = 2; // 忙碌


    //call_status

    const ROBOT_FREE = 0; //有空
    const ROBOT_USR = 1; //占线
    const ROBOT_WAIT = 2; //等待中


    //status
    const ROBOT_ONLINE = 1; //在线
    const ROBOT_OFFLINE = 0; //离线

    public static function onWorkerStart($worker)
    {
        devlog("onWorkerStart_Events");
    }

    public static function onConnect($client_id)
    {
        // devlog("onConnect $client_id");

    }

    //某些情况将不会触发onWorkerStop，例如业务出现致命错误FatalError，或者进程被强行杀死等情况。
    public static function onWorkerStop($businessWorker)
    {
        devlog("WorkerStop ");
    }

    public static function onWebSocketConnect($client_id, $data)
    {
        //  devlog("onWebSocketConnect $client_id");

        //   devlog($data);

    }

    public static function onMessage($client_id, $message)
    {
        $receivejsondata = $message;
        $data = json_decode($receivejsondata, true);
        $APP_DEBUG = getenv("APP_DEBUG");
        if ($APP_DEBUG) {
            devlog($message);
        }
        $fd = $client_id;
        $role = isset($data["role"]) ? $data["role"] : "";
        $cmd = isset($data["cmd"]) ? $data["cmd"] : "";

        if ($cmd == "connect") {
            self::connect($fd, $data);
        } else {
            if ($role == "robot_coach") {

                //机器人
                switch ($cmd) {
                    case "callsur":
                        //手动呼叫监控
                        self::robotCallSurveillance($fd); //robot_coach 手动呼叫监控
                        break;
                    //
                    case "stagewarn":
                        self::stagewarn($fd, $data);
                        break;

                    case "close":
                        self::closerobot($fd, $data);
                        break;
                    case "ack":


                        //   self::robotack($fd, $data);
                        break;

                    case "heartbeat":
                        self::robotheartbeat($fd, $data); //robot_coach
                        break;
                    case "userlogin":
                        self::userlogin($fd, $data);
                        break;
                    case "userlogout":
                        self::userlogout($fd, $data);
                        break;
                    case "carsync":
                        //同步数据
                        self::robotcarsync($fd, $data); //carsync
                        break;


                    case "autocallsur":
                        self::robotautocallsur($fd);
                        break;


                    case "addError":

                        self::addError($fd, $data);
                        break;
                    case "robot_alert":
                        self::robot_alert($data);
                        break;
                    case "robot_toast":
                        self::robot_toast($data);
                        break;
                    case "startpass":
                        self::startpass($data);
                        break;
                    case "endpass":
                        self::endpass($data);
                        break;

                    case "inframe":

                        self::inframe($fd, $data);
                        break;

                    case "outframe":
                        self::outframe($fd, $data);

                        break;


                    default:
                }
            } else if ($role == "surveillance") {

                //监控
                switch ($cmd) {
                    case "rcconnect":
                        self::rcconnect($fd, $data);

                        break;

                    case "ack":
                        self::ack($fd, $data);

                        break;
                    case "heartbeat":
                        self::surveillanceheartbeat($fd, $data);
                        break;

                    case "callrobot":
                        //语音 呼叫机器人
                        self::callrobot($fd, $data);
                        break;
                    case "reject":
                        //拒绝通话
                        self::surreject($fd, $data);
                        break;

                    case "coachreject":
                        //拒绝通话
                        self::surcoachreject($fd, $data);
                        break;
                    case "hangup":
                        //挂断电话
                        self::hangup($fd, $data);
                        break;
                    case "brake":
                        //刹车
                        self::brake($fd, $data);
                        break;

                    case "stopbrake":
                        //刹车
                        self::stopbrake($data);
                        break;
                    //
                    case "changeCallStatus":
                        self::surChangeCallStatus($fd, $data);
                        break;


                    default:
                }
            } elseif ($role == "sub3robot") {
                //机器人
                switch ($cmd) {


                    case "heartbeat":
                        self::robotheartbeat($fd, $data); //sub3robot
                        break;
                    case "callsur":
                        //手动呼叫监控
                        self::robotCallSurveillance($fd);
                        break;
                    case "carsync":
                        //同步数据
                        self::sub3robotcarsync($fd, $data);
                        break;


                    default:
                }
            } else {
            }
        }
    }

    public static function inframe($fd, $data)
    {


        //  devlog("inframe");
        $frameid = $data["frameid"];
        $key = "getrobotfdbyframeid:{$frameid}";
        $deviceinfo = self::getDeviceInfoByFd($fd);
        //  devlog($deviceinfo);
        // {"coach_name":"未绑定","car_number":"287","robot_id":4,"pickup_ip":"192.168.0.164","shift_type":1,"imei":"PC210519320185Default string","master_school_id":12647,"coach_id":0,"call_status":0,"status":1,"error_list":[],"student_id":0,"student_name":"","errnum":0,"backcolor":"green","nomc":0,"ip":"192.168.0.49","fd":"7f00000108fc00000014","role":"robot_coach","name":"","surimei":"27"}
        $car_number = "";
        $robot_id = 0;
        if ($deviceinfo) {
            $robot_id = $deviceinfo["robot_id"];

            $car_number = $deviceinfo["car_number"];
        }
        //      $imei = $deviceinfo["imei"];
        //   devlog("{$car_number}|inframe:{$frameid}");
        Base::redisSet($key, $fd, 3600);
        $host = getenv("host");
        $url = "{$host}api/lsods/inframe";
        $post["robot_id"] = $robot_id;
        $post["frameid"] = $frameid;
        Base::curlpost($url, $post);
    }

    public static function outframe($fd, $data)
    {
        //     devlog("outframe");
        $frameid = $data["frameid"];
        $deviceinfo = self::getDeviceInfoByFd($fd);
        $car_number = "";
        $robot_id = 0;
        if ($deviceinfo) {
            $car_number = $deviceinfo["car_number"];
            $robot_id = $deviceinfo["robot_id"];
        }
        //   devlog("{$car_number}|outframe:{$frameid}");
        $key = "getrobotfdbyframeid:{$frameid}";
        Redis::del($key);
        $host = getenv("host");
        $url = "{$host}api/lsods/outframe";
        $post["robot_id"] = $robot_id;
        $post["frameid"] = $frameid;
        Base::curlpost($url, $post);
    }


    public static function stagewarn($robotfd, $data)
    {
        //  devlog($data);
        $robotinfo = self::getDeviceInfoByFd($robotfd);


        $robotimei = $robotinfo["imei"];
        $warn_num = $data["warn_num"];

        $key = "stagewarnByfd:{$robotfd}";


        $own = Base::redisGet($key);

        if ($warn_num > $own) {
            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "setstagewarn"; //设置警报数
            $surdata["data"]["imei"] = $robotimei;
            $surdata["data"]["warn_num"] = $warn_num;

            //   devlog($surdata);
            self::broadcastsur($surdata);
        }

        Base::redisSet($key, $warn_num, 3600 * 6);
    }

    public static function closerobot($fd, $data)
    {
        devlog("closerobot:{$fd}");
        $deviceinfo = self::getDeviceInfoByFd($fd);
        $car_number = $deviceinfo["car_number"];
        devlog("closerobot:{$fd}:{$car_number}");
        Base::toast("{$car_number}主动断开连接");

        self::disconnect($fd);
    }

    public static function robotack($fd, $data)
    {
        $deviceinfo = self::getDeviceInfoByFd($fd);
        $car_number = $deviceinfo["car_number"];
        $ackcmd = $data["ackcmd"];
        $msgid = $data["msgid"];
        if ($ackcmd == "surcallin") {


            devlog("ackcmd:surcallin:{$car_number}:{$msgid}");

            $timekey = "pushJsonid:{$ackcmd}:{$fd}:{$msgid}";
            $sendtime = Base::redisGet($timekey);
            if ($sendtime) {
                $utime = time() - $sendtime;

                devlog("surcallin:use time {$utime}");

                if ($utime > 2) {
                    $toastmsg = "{$car_number}内网延迟{$utime}秒";

                    Base::toast($toastmsg);
                } else {
                    $toastmsg = "{$car_number}收到监控呼叫";

                    Base::toast($toastmsg);
                }
            } else {
                devlog("surcallin:no sendtime");
                $toastmsg = "{$car_number}收到监控呼叫 no sendtime";

                Base::toast($toastmsg);
            }
        } elseif ($ackcmd == "testws") {

            $ackkey = "ackcount:{$ackcmd}:{$fd}";


            $ackcount = Base::redisIncr($ackkey);
            devlog("testws_ack:{$fd}:{$car_number} msgid:{$msgid} ack:{$ackcount}");
            if ($ackcount != $msgid) {

                devlog("testws_ack:err:{$fd}:{$car_number} msgid:{$msgid} !=ack:{$ackcount}");
            }
        } else {
            devlog($data);
        }


        //   $ackkey = "robotackcount:{$ackcmd}:{$fd}";


        //  $ackcount = Base::redisIncr($ackkey);

        //        if ($ackcount != $msgid) {
        //
        //            $key = "broadcastsurid:{$ackcmd}:{$fd}";
        //            $sendcount = Base::redisGet($key);
        //            if ($sendcount != $ackcount) {
        //                devlog("msgid:{$msgid} send:{$sendcount}!=ack:{$ackcount}");
        //
        //            }
        //
        //        }

    }

    public static function ack($fd, $data)
    {

        $ackcmd = $data["ackcmd"];
        $msgid = $data["msgid"];


        $ackkey = "ackcount:{$ackcmd}:{$fd}";


        $ackcount = Base::redisIncr($ackkey);

        if ($ackcount != $msgid) {

            $key = "broadcastsurid:{$ackcmd}:{$fd}";
            $sendcount = Base::redisGet($key);
            if ($sendcount != $ackcount) {
                //  devlog("msgid:{$msgid} send:{$sendcount}!=ack:{$ackcount}");

            }
        }
    }

    public static function robotheartbeat($fd, $data)
    {
        $now = time();
        $imei = isset($data["imei"]) ? $data["imei"] : "";
        if (!$imei) {
            devlog("no imei robotheartbeat robotfd:{$fd}");
            return;
        }
        $ts = isset($data["ts"]) ? $data["ts"] : 0;
        $reqid = isset($data["reqid"]) ? $data["reqid"] : 0;
        $utime = "";
        $deviceinfo = self::getDeviceInfoByFd($fd);
        if (!isset($deviceinfo["subject"])) {
            devlog("no subject:");
            devlog($deviceinfo);
        }


        if (!$deviceinfo) {
            devlog("no deviceinfo robotheartbeat robotfd:{$fd}");

            return;
        }

        $subject = $deviceinfo["subject"];
        $car_number = "";
        if ($deviceinfo) {
            $car_number = $deviceinfo["car_number"];
        }
        if ($ts) {
            $utime = $now - $ts;
            if (abs($utime) > 5) {


                $toastmsg = "{$car_number}心跳网络延迟{$utime}秒";
                //  devlog($toastmsg);

                //  Base::toast($toastmsg);


            }
        }

        //     devlog("$car_number({$fd}) 心跳");

        //30秒一次心跳
        $time = time();
        $robotheartbeaimeitkey = "robotheartbeatimei:{$imei}";
        Base::redisSet($robotheartbeaimeitkey, $time, 600);

        $robotschool_id = $deviceinfo["school_id"];
        if ($subject == 3) {
            $robotheartbeaimeitkey = "robot3heartbeatimei:{$imei}";
            Base::redisSet($robotheartbeaimeitkey, $time, 600);
        }
        //发送给监控
        self::changeRobotStatus(self::ROBOT_ONLINE, $imei); //robotheartbeat
        $surdata["code"] = 0;
        $surdata["msg"] = "";
        $surdata["data"]["cmd"] = "robotstatus";
        $surdata["data"]["status"] = 1;
        $surdata["data"]["imei"] = $imei;
        $robot_id = $surdata["data"]["robot_id"] = $deviceinfo["robot_id"];
        $surdata["data"]["car_number"] = $deviceinfo["car_number"];

        self::broadcastsur($surdata); //robotstatus

        //1    2
        //       1     2
        $rdata = [];
        $rdata["code"] = 0;
        $sendt = date("i:s", $ts);
        $receivet = date("i:s", $now);
        $rdata["msg"] = "car_number:{$car_number} reqid:{$reqid} send:{$sendt} receive:{$receivet} utime:{$utime}秒";

        $rdata["data"]["cmd"] = "receiveheartbeat";
        $rdata["data"]["receivecmd"] = "heartbeat";
        $rdata["data"]["sendts"] = $ts;
        $rdata["data"]["receivets"] = $now;
        $rdata["data"]["reqid"] = $reqid;
        $rdata["data"]["utime"] = $utime;
        $rdata["data"]["msgid"] = 0;


        //todo  发送收到请求
        Base::pushJson($rdata, $fd);


        //   return $rdata;

    }

    public static function userlogin($client_id, $data)
    {


        $fd = $client_id;
        $robotinfo = self::getDeviceInfoByFd($fd);
        if ($robotinfo && $robotinfo["role"] == self::ROLE_ROBOT) {
            $student_id = isset($data["student_id"]) ? $data["student_id"] : "";
            $studentinfo = self::getStudentById($student_id);
            if (!isset($studentinfo["student_name"])) {
                $student_name = "学员端有BUG{$student_id}|";
            } else {
                $student_name = $studentinfo["student_name"];
            }

            $robotimei = $robotinfo["imei"];
            $md = date("md");

            $loginkey = "userloginbyimei:{$md}:{$robotimei}";
            Base::redisSet($loginkey, time(), 3600 * 24);

            self::changeRobotStudent($student_name, $student_id, $robotimei);
            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "studentrobot"; //登录
            $surdata["data"]["studytime"] = 0;

            $surdata["data"]["student_id"] = $student_id;
            $surdata["data"]["student_name"] = $student_name;
            $robot_id = $robotinfo["robot_id"];

            $surdata["data"]["robot_id"] = $robot_id;
            $surdata["data"]["imei"] = $robotimei;
            $surdata["data"]["status"] = 1;
            self::broadcastsur($surdata);

            $car_number = $robotinfo["car_number"];

            $coachinfo = Base::getCoachByStudent($student_id);
            $coach_name = "";
            if ($studentinfo) {
                if ($studentinfo["school_id"] == 12647) {
                    $coach_name = $coachinfo ? $coachinfo["coach_name"] . "的学员：" : "";
                }
            }


            $toastmsg = "{$coach_name}$student_name 登录 {$car_number}"; //1

            Base::toast($toastmsg);


            $surdata = [];
            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "setstagewarn"; //设置警报数
            $surdata["data"]["imei"] = $robotimei;
            $surdata["data"]["warn_num"] = 0;
            self::broadcastsur($surdata);
            //   devlog($toastmsg);


        }
    }

    public static function getStudentById($student_id)
    {
        if (!$student_id) {
            return [];
        }
        $getStudentByIdkey = "getStudentById:{$student_id}";
        $studentinfo = $redis = Base::redisGetArr($getStudentByIdkey);
        if (!$studentinfo) {
            $host = getenv("host");
            $url = "{$host}api/lsods/getStudentById";
            $post["student_id"] = $student_id;
            $rt = Base::curlpost($url, $post);
            //  devlog("api/lsods/getStudentById:{$student_id}");
            //  devlog($rt);
            if ($rt["code"] == 0) {
                $studentinfo = $rt["data"]["studentinfo"];
                Base::redisSetArr($getStudentByIdkey, $studentinfo, 3600 * 24);
            }
        }
        return $studentinfo;
    }

    public static function changeRobotStudent($student_name, $student_id, $imei)
    {

        $robotinfo = self::getRobotInfoByImei($imei);
        $robotinfo["student_name"] = $student_name;
        $robotinfo["student_id"] = $student_id;


        self::setRobotInfoByImei($imei, $robotinfo); //changeRobotStudent

    }


    public static function userlogout($client_id, $data)
    {
        ///      devlog("userlogout");
        $fd = $client_id;
        $deviceinfo = self::getDeviceInfoByFd($fd);
        if ($deviceinfo && $deviceinfo["role"] == self::ROLE_ROBOT) {
            $imei = $deviceinfo["imei"];
            self::changeRobotStudent("", 0, $imei);
            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "studentrobot"; //退出
            $robot_id = $deviceinfo["robot_id"];

            $surdata["data"]["student_name"] = "-";
            $surdata["data"]["student_id"] = 0;
            $surdata["data"]["studytime"] = 0;
            $surdata["data"]["imei"] = $deviceinfo["imei"];
            $surdata["data"]["robot_id"] = $robot_id;
            $surdata["data"]["status"] = 0;
            self::broadcastsur($surdata);

            $md = date("md");
            $loginkey = "userloginbyimei:{$md}:{$imei}";

            Redis::del($loginkey);

            //  devlog("userlogout $loginkey");

            //self::clearerrnum($imei);

            $rdata["code"] = 0;
            $rdata["msg"] = "success";
            $rdata["data"]["cmd"] = "logoutsuccess";
            return $rdata;
        }
    }

    public static function stopcar($imei, $minute)
    {


        $surdata["code"] = 0;
        $surdata["msg"] = "";
        $surdata["data"]["cmd"] = "setstopcarminute"; //设置停车分钟
        $surdata["data"]["imei"] = $imei;
        $surdata["data"]["minute"] = $minute;
        self::broadcastsur($surdata);
    }

    public static function checkspeed($fd, $speed)
    {
        $robotinfo = self::getDeviceInfoByFd($fd);
        $robotimei = $robotinfo["imei"];
        $car_number = $robotinfo["car_number"];
        $key = "stopcar:{$fd}";
        $min = 0.3;
        //0.096
        if ($speed < $min) {

            $now = time();


            $starttime = Base::redisGet($key);

            if ($starttime) {


                $utime = $now - $starttime;

                if ($utime >= 60) {

                    if ($utime & 60 == 0) {
                        $t = $utime / 60;


                        if (!$robotinfo) {
                            devlog("没有找到robotinfo");

                            return;
                        }


                        $key = "checkspeed:{$fd}:{$t}";
                        $value = Base::redisGet($key);

                        if (!$value) {
                            Base::redisSet($key, 1, 3);
                            $toastmsg = "{$car_number} 原地停留{$t}分钟";
                            Base::toast($toastmsg);


                            self::stopcar($robotimei, $t);
                        }
                    }
                }
            } else {

                //开始计时
                Base::redisSet($key, $now, 3600 * 12);
            }
        } else {
            $starttime = Base::redisGet($key);
            if ($starttime) {
                self::stopcar($robotimei, 0);
                Redis::del($key);
            }
        }
    }

    //sub3robotcarsync
    public static function sub3robotcarsync($client_id, $data)
    {


        $GPS = $data["GPS"];
        $OBD = $data["OBD"]; //每两秒推送给驾校
        $RealPosition = $data["RealPosition"];
        $RealRotation = $data["RealRotation"];
        $Timestamp = $data["Timestamp"];
        $Student_id = isset($data["Student_id"]) ? $data["Student_id"] : 0;
        $deviceinfo = self::getDeviceInfoByFd($client_id);

        if (!$deviceinfo) {

            //  self::devlog("robotcarsync no deviceinfo {$fd}");

            $rdata = [
                "code" => 0,
                "msg" => "no deviceinfo",
                "data" => [
                    "cmd" => "error"
                ]
            ];
            return $rdata;
        }
        $robot_id = $deviceinfo["robot_id"];

        $car_number = $deviceinfo["car_number"];


        // devlog("{$car_number} sub3robotcarsync");

        $fd = $client_id;
        //todo 判断长时间停留
        // $master_school_id = $deviceinfo["master_school_id"];

        //机器人信息

        $imei = $deviceinfo["imei"];
        $rdata["code"] = 0;
        $rdata["msg"] = "sub3";
        $rdata["data"]["cmd"] = "robotcarsync";
        $robotinfo["imei"] = $imei;
        $robotinfo["GPS"] = $GPS;
        $robotinfo["OBD"] = $OBD;
        $robotinfo["RealPosition"] = $RealPosition;
        $robotinfo["RealRotation"] = $RealRotation;
        $rdata["data"]["robotinfo"] = $robotinfo;
        //  devlog($rdata);

        base::broadcastsur($rdata);
        $school_id = getenv("school_id");
        //  $robotschool_id = $deviceinfo["school_id"];


        //   $sub3robotdata["car_number"] = $car_number;
        //    $sub3robotdata["robot_id"] = $robot_id;
        //     $sub3robotdata["RealPosition"] = $RealPosition;
        //    $sub3robotdata["RealRotation"] = $RealRotation;

        //  self::broadcastsub3robot($sub3robotdata, $client_id);

        $rdata = [
            "code" => 0,
            "msg" => "receive data",
            "data" => [
                "cmd" => "ok"
            ]

        ];

        return $rdata;
    }

    public static function robotcarsync($client_id, $data)
    {

        //{"code":0,"msg":"","data":{"cmd":"robotcarsync","robotinfo":{"imei":"6e196a97f8a205d5d7fc7991f0e27367dea7b4ac","GPS":"$GPS,5.44,0.096,+4144189.348,+534147.602,3,4,*4f","OBD":"$OBD,1,0,783,0,0,32796,0,0,0,1,0,0,3,0,0,0,0,0,0,0,0,*5b","RealPosition":"8.04,0,4.39","RealRotation":"0,105.0761,0"},"msgid":881}}


        //{"cmd":"carsync","role":"robot_coach","GPS":"$GPS,5.44,0.096,+4144189.348,+534147.602,3,4,*4f","OBD":"$OBD,1,0,783,0,0,32796,0,0,0,1,0,0,3,0,0,0,0,0,0,0,0,*5b","RealPosition":"0,0,0","RealRotation":"0,0,0","student_id":"259753","Timestamp":"1713166246149","error_code":""}
        //GPS: "$GPS,5.44,0.096,+4144189.348,+534147.602,3,4,*4f"


        //$OBD,1,0,783,0,0,32796,0,0,0,1,0,0,3,0,0,0,0,0,0,0,0,*5b

        //        devlog("robotcarsync");
        //    $content=$data["content"];
        $GPS = $data["GPS"];
        $OBD = $data["OBD"]; //每两秒推送给驾校
        $RealPosition = $data["RealPosition"];
        $RealRotation = $data["RealRotation"];
        $Timestamp = $data["Timestamp"];
        $Student_id = isset($data["Student_id"]) ? $data["Student_id"] : 0;
        $deviceinfo = self::getDeviceInfoByFd($client_id);

        if (!$deviceinfo) {

            //  self::devlog("robotcarsync no deviceinfo {$fd}");

            $rdata = [
                "code" => 0,
                "msg" => "no deviceinfo",
                "data" => [
                    "cmd" => "error"
                ]
            ];
            return $rdata;
        }
        $car_number = $deviceinfo["car_number"];
        $fd = $client_id;
        //todo 判断长时间停留
        $master_school_id = $deviceinfo["master_school_id"];
        if ($master_school_id == 12647) {
            $robot_id = $deviceinfo["robot_id"];
            $postobdkey = "postobd:{$robot_id}";

            if ($OBD) {
                if (!Base::redisGet($postobdkey)) {

                    Base::redisSet($postobdkey, 1, 2);

                    $host = getenv("host");
                    $url = "{$host}api/lsods/postobd";

                    $post["robot_id"] = $robot_id;
                    $post["obd"] = $OBD;
                    $post["gps"] = $GPS;
                    Base::curlpost($url, $post);
                }
            }
        }

        $gpsarr = explode(",", $GPS);

        if (!isset($gpsarr[2])) {

            $key = "GPSerrtimeout";
            $value = Base::redisGet($key);
            if (!$value) {
                Base::redisSet($key, 1, 10);

                $toastmsg = "{$car_number}GPS异常{$GPS}";
                devlog($toastmsg);

                Base::toast($toastmsg);
            }
        } else {
            $speed = $gpsarr[2];
            self::checkspeed($fd, $speed);
        }


        //机器人信息


        $imei = $deviceinfo["imei"];
        $rdata["code"] = 0;
        $rdata["msg"] = "";
        $rdata["data"]["cmd"] = "robotcarsync";
        $robotinfo["imei"] = $imei;
        $robotinfo["GPS"] = $GPS;
        $robotinfo["OBD"] = $OBD;
        $robotinfo["RealPosition"] = $RealPosition;
        $robotinfo["RealRotation"] = $RealRotation;
        $rdata["data"]["robotinfo"] = $robotinfo;


        self::broadcastsur($rdata);

        $school_id = getenv("school_id");

        if ($school_id == 12794 || $school_id == 12843) {

            //哈哈计时
        }


        $rdata = [
            "code" => 0,
            "msg" => "receive data",
            "data" => [
                "cmd" => "ok"
            ]

        ];

        return $rdata;
    }
    //  30秒不接听 监控自动挂断
    //29秒


    public static function robotCallSurveillance($robotfd, $toastmsg = "")
    {

        //机器人必须绑定教练才能呼叫远控
        devlog("机器人 呼叫监控 robotfd：$robotfd {$toastmsg}");
        $robotinfo = self::getDeviceInfoByFd($robotfd);
        if (!$robotinfo) {
            devlog("没有找到robotinfo");

            return;
        }
        $robotimei = $robotinfo["imei"];
        $car_number = $robotinfo["car_number"];
        devlog("机器人 呼叫监控 callsur robotfd：$robotfd 车牌号:{$car_number} {$toastmsg}");
        $robotinfobyimei = self::getRobotInfoByImei($robotimei);
        $student_id = isset($robotinfobyimei["student_id"]) ? $robotinfobyimei["student_id"] : 0;
        $school_id = getenv("school_id");
        //科二训练场 （太阳谷训练场）[12794]

        //   科二训练场 （德院训练场）[12843]
        $master_school_id = $robotinfo["master_school_id"];

        if ($master_school_id == 12647) {
            if (!isset($robotinfobyimei["student_id"]) || !$robotinfobyimei["student_id"]) {

                // 学员未登录 随机找一个远控
                devlog("学员未登录 随机找一个远控 {$car_number}");
                Base::toast("学员未登录呼叫教练");

                $rcsurveillancelist = self::getRCSurveillanceList();
                if (!$rcsurveillancelist) {
                    devlog("没有远控在线:");
                    devlog($rcsurveillancelist);
                    Base::toast("没有远控在线");

                    return;
                }
                shuffle($rcsurveillancelist);
                foreach ($rcsurveillancelist as $k => $v) {
                    //  随机找一个远控 呼叫

                    $robot_id = $robotinfo["robot_id"];

                    $surfd = $v["fd"];
                    $surdata["code"] = 0;
                    $surdata["msg"] = "{$car_number}呼叫你";
                    $surdata["data"]["cmd"] = "callin"; //学员未登录
                    $surdata["data"]["imei"] = $robotimei;
                    $surdata["data"]["car_number"] = $car_number;
                    $surdata["data"]["robot_id"] = $robot_id;


                    $key = "broadcastsurid:callin:{$surfd}";
                    $broadcastsurid = Base::redisIncr($key);
                    $surdata["data"]["msgid"] = $broadcastsurid;

                    devlog($surdata);

                    Base::pushJson($surdata, $surfd); //callin

                    return;
                }
            }
        }

        devlog($robotinfo);
        $robot_coach_id = $robotinfo["rc_coach_id"]; //初始化接口 api/lsods/getrobotinfobyimei 获得 数据库 robot表 rc_coach_id 字段
        if ($robot_coach_id) {
            //外部驾校使用 江苏路通
            devlog("外部驾校机器人{$robotfd} coach_id {$robot_coach_id}");

            $surfd = self::getSurFdByCoachId($robot_coach_id);
            devlog("外部驾校机器人{$robotfd} surfd {$surfd}");

            if (!$surfd) {
                devlog("机器人{$robotfd} no_surfd 监控没有开机:coach_id:{$robot_coach_id} ");


                // 普通驾校最好不要在机器人上添加预约教练 会导致呼叫不了监控
                $rdata["code"] = 0;
                $rdata["msg"] = "监控没有开机:coach_id:{$robot_coach_id}";
                $rdata["data"]["cmd"] = "nosuronline";
                Base::pushJson($rdata, $robotfd); //nosuronline
            }
            $surinfo = self::getDeviceInfoByFd($surfd);

            if (!$surinfo) {
                devlog("机器人{$robotfd} surfd:{$surfd} no surinf ");

                return;
            }

            $call_status = isset($surinfo["call_status"]) ? $surinfo["call_status"] : self::SUR_FREE;

            devlog("机器人{$robotfd} surfd:{$surfd} call_status {$call_status}");

            if ($call_status == self::SUR_FREE) {
                devlog("机器人{$robotfd}正常通话");

                //正常通话

                $rdata["code"] = 0;
                $rdata["msg"] = "ok";
                $rdata["data"]["cmd"] = "wait";
                Base::pushJson($rdata, $robotfd); //wait
                //问问监控同意不同意
                $surimei = $surinfo["imei"];
                self::changeDeviceCallStatus($surfd, self::SUR_USE);
                $surinfobyimei = Base::getSurinfoByImei($surimei); //获取监控pid

                $surpid = $surinfobyimei["pid"];
                if ($surpid) {
                    //                    //远程控制
                    $robot_id = $robotinfo["robot_id"];
                    $surdata["code"] = 0;
                    $surdata["msg"] = "{$car_number}呼叫你";
                    $surdata["data"]["cmd"] = "callin";
                    $surdata["data"]["imei"] = $robotimei;
                    $surdata["data"]["car_number"] = $car_number;
                    $surdata["data"]["robot_id"] = $robot_id;
                    devlog($surdata);
                    Base::pushJson($surdata, $surfd); //callin

                } else {
                    //监控
                    $surdata["code"] = 0;
                    $surdata["msg"] = "{$car_number}呼叫你";
                    $surdata["data"]["cmd"] = "callin";
                    $surdata["data"]["imei"] = $robotimei;
                    Base::pushJson($surdata, $surfd);
                }

                //记录数据库 手动呼叫 todo

                self::addhandwarning($student_id);
            } else {
                //监控占线

                $surimei = $surinfo["imei"];
                Base::toast("监控{$surimei}占线");

                devlog("监控{$surimei}占线");


                //没有监控接
                $rdata["code"] = 0;
                $rdata["msg"] = "ok";
                $rdata["data"]["cmd"] = "nosurfree";
                Base::pushJson($rdata, $robotfd); //nosurfree
                //修改机器人状态为等待

                self::changeRobotCallStatusByImei($robotimei, self::ROBOT_WAIT);
                self::changeDeviceCallStatus($robotfd, self::ROBOT_WAIT);
            }


            return;
        } else {

            //快鸭驾校 机器人没有绑定教练  咸阳秉诚科二训练场[13587]
            devlog("机器人 呼叫监控 callsur robotfd：$robotfd {$car_number} 无教练");

            devlog($robotinfobyimei);


            //     devlog("学员登录  {$car_number}");


            if (!$student_id) {


                $toastmsg = "未登录学员呼叫教练";
                devlog("$toastmsg");

                Base::toast($toastmsg);
            }


            // todo 因为学员登录的是教练的号 所以没法按学员ID找到正确的远控 只能呼叫监控
            $coachinfo = Base::getCoachByStudent($student_id);


            devlog("学员登录  {$car_number} 根据学员{$student_id}找教练");


            if ($coachinfo) {
                $coach_name = $robotinfo["coach_name"] = $coachinfo["coach_name"];
                $coach_id = $robotinfo["coach_id"] = $coachinfo["coach_id"];


                devlog("快鸭驾校机器人 呼叫监控 callsur getCoachBystudent_id:{$student_id} |coach_id:{$coach_id}  {$coach_name}");


                if ($coach_name && $coach_name != "未绑定") {

                    $toastmsg = "{$toastmsg} {$car_number} 呼叫 {$coach_name}";

                    Base::toast($toastmsg);
                }
            } else {

                $studentinfo = self::getStudentById($student_id);
                $student_name = $studentinfo ? $studentinfo["student_name"] : "未登录";
                devlog("学员{$student_id}:{$student_name} 根据学员{$student_id}找不到教练");

                $coach_id = 0;
            }


            //   self::devlog("机器人 呼叫监控 robotimei：$robotimei coach_id：{$coach_id}");
            $robot_id = $robotinfo["robot_id"];

            if ($coach_id) {

                //学员绑定教练
                // todo  安弘驾校城北训练场[13228] 6330 数据库没有教练 但是到这里变成了有教练 需要继续排查

                $surfd = self::getSurFdByCoachId($coach_id);
                //快鸭驾校机器人 呼叫监控 robot_id:680|coach_id:3795 surfd：
                /**
                 *
                 * [2025-05-13 16:29:33] default.INFO: 快鸭驾校机器人 呼叫监控 callsur robot_id:4|coach_id:889 surfd：7f00000108fc00000050
                 * [2025-05-13 16:29:33] default.INFO: 监控 有空
                 * [2025-05-13 16:29:33] default.INFO: {"surveil_id":18,"imei":"18","school_id":12794,"remark":"王宇","coach_id":889,"rcimei":"","pid":0,"status":1,"ctime":0}
                 * [2025-05-13 16:29:33] default.INFO: surpid:0 胡 应该有 但是没有
                 * [2025-05-13 16:29:33] default.INFO: 呼叫监控 18
                 */
                //     devlog("快鸭驾校机器人 呼叫监控 callsur robot_id:{$robot_id}|coach_id:{$coach_id} surfd：{$surfd}");

                //运行到这里中断 TODO 查BUG
                if (!$surfd) {
                    devlog("快鸭驾校机器人 呼叫监控 callsur nosuronline");
                    $rdata["code"] = 0;
                    $rdata["msg"] = "ok";
                    $rdata["data"]["cmd"] = "nosuronline";
                    Base::pushJson($rdata, $robotfd); //nosuronline

                }
                $surinfo = self::getDeviceInfoByFd($surfd);
                if (!$surinfo) {
                    devlog("快鸭驾校机器人 呼叫监控 no surinfo");
                    return;
                }

                $call_status = isset($surinfo["call_status"]) ? $surinfo["call_status"] : self::SUR_FREE;
                if ($call_status == self::SUR_FREE) {
                    /**
                     *
                     * [2025-05-13 16:29:33] default.INFO: 监控 有空
                     * [2025-05-13 16:29:33] default.INFO: {"surveil_id":18,"imei":"18","school_id":12794,"remark":"王宇","coach_id":889,"rcimei":"","pid":0,"status":1,"ctime":0}
                     * [2025-05-13 16:29:33] default.INFO: surpid:0 胡 应该有 但是没有
                     * [2025-05-13 16:29:33] default.INFO: 呼叫监控 18
                     */
                    devlog("监控 有空");

                    //正常通话

                    $rdata["code"] = 0;
                    $rdata["msg"] = "ok";
                    $rdata["data"]["cmd"] = "wait";
                    Base::pushJson($rdata, $robotfd); //wait


                    //问问监控同意不同意

                    $surimei = $surinfo["imei"];

                    self::changeDeviceCallStatus($surfd, self::SUR_USE);
                    $surinfobyimei = Base::getSurinfoByImei($surimei); //$surinfobyimei["pid"];

                    /**
                     *
                     * [2025-05-13 16:29:33] default.INFO: {"surveil_id":18,"imei":"18","school_id":12794,"remark":"王宇","coach_id":889,"rcimei":"","pid":0,"status":1,"ctime":0}
                     */
                    // todo 这里有问题 找到的是监控

                    /**
                     *
                     * [2025-05-13 16:29:33] default.INFO: {"surveil_id":18,"imei":"18","school_id":12794,"remark":"王宇","coach_id":889,"rcimei":"","pid":0,"status":1,"ctime":0}
                     * [2025-05-13 16:29:33] default.INFO: surpid:0 胡 应该有 但是没有
                     * [2025-05-13 16:29:33] default.INFO: 呼叫监控 18
                     */
                    $surpid = $surinfobyimei["pid"];
                    if ($surpid == 0) {
                        devlog("根据教练{$coach_id}查找不到远控|转到监控{$surimei}");
                    }
                    if ($surpid) {
                        //远程控制 胡 走不到这里
                        devlog("呼叫远控 {$surimei}");
                        $surdata["code"] = 0;
                        $surdata["msg"] = "{$car_number}呼叫你";
                        $surdata["data"]["cmd"] = "callin"; //已登录学员呼叫远控
                        $surdata["data"]["imei"] = $robotimei;
                        $surdata["data"]["car_number"] = $car_number;
                        $surdata["data"]["robot_id"] = $robot_id;
                        $key = "broadcastsurid:callin:{$surfd}";
                        $broadcastsurid = Base::redisIncr($key);
                        $surdata["data"]["msgid"] = $broadcastsurid;
                        devlog($surdata);
                        Base::pushJson($surdata, $surfd); //callin
                        self::startrobotcall($student_id, $robotinfo, $coach_id);
                    } else {
                        //走到了这里
                        devlog("呼叫监控 {$surimei}");
                        $surdata["code"] = 0;
                        $surdata["msg"] = "{$car_number}呼叫你";
                        $surdata["data"]["cmd"] = "callin"; //呼叫监控
                        $surdata["data"]["imei"] = $robotimei;
                        Base::pushJson($surdata, $surfd); //callin

                    }

                    //记录数据库 手动呼叫 todo

                    self::addhandwarning($student_id);
                    //         self::devlog("callin surfd:$surfd");


                    return;
                } else {
                    //监控占线
                    devlog("监控占线");

                    //没有监控接
                    $rdata["code"] = 0;
                    $rdata["msg"] = "ok";
                    $rdata["data"]["cmd"] = "nosurfree";
                    Base::pushJson($rdata, $robotfd); //nosurfree
                    //修改机器人状态为等待

                    self::changeRobotCallStatusByImei($robotimei, self::ROBOT_WAIT);
                    self::changeDeviceCallStatus($robotfd, self::ROBOT_WAIT);

                    //开始累计未接来电

                    //        $this->numberofmissedcalls($robotimei, $surfd);


                    return;
                }


                return;
            } else {
                //学员没有绑定教练


                $school_id = getenv("school_id");
                if ($school_id == 12693) {
                    //     快鸭测试驾校[12693]

                    $surfd = self::getSurFdByCoachId(21);

                    $surdata["code"] = 0;
                    $surdata["msg"] = "{$car_number}呼叫你";
                    $surdata["data"]["cmd"] = "callin";
                    $surdata["data"]["imei"] = $robotimei;
                    $surdata["data"]["car_number"] = $car_number;
                    $surdata["data"]["robot_id"] = $robot_id;
                    Base::pushJson($surdata, $surfd); //callin


                }


                $rcsurveillancelist = self::getRCSurveillanceList();

                if ($rcsurveillancelist) {
                    shuffle($rcsurveillancelist);
                    foreach ($rcsurveillancelist as $k => $v) {
                        //  随机找一个远控 呼叫

                        $robot_id = $robotinfo["robot_id"];

                        $surfd = $v["fd"];
                        $surdata["code"] = 0;
                        $surdata["msg"] = "{$car_number}呼叫你";
                        $surdata["data"]["cmd"] = "callin"; //学员未登录
                        $surdata["data"]["imei"] = $robotimei;
                        $surdata["data"]["car_number"] = $car_number;
                        $surdata["data"]["robot_id"] = $robot_id;


                        $key = "broadcastsurid:callin:{$surfd}";
                        $broadcastsurid = Base::redisIncr($key);
                        $surdata["data"]["msgid"] = $broadcastsurid;

                        devlog($surdata);

                        Base::pushJson($surdata, $surfd); //callin

                        return;
                    }
                }


                //机器人随机呼叫
                $surlist = self::getSurveillanceList();
                if ($surlist) {
                    //   没有监控开机
                    $rejectlistbyimeikey = "rejectlistbyimei::{$robotimei}";
                    $rejectlist = Base::redisGetArr($rejectlistbyimeikey);
                    $rejectlist = $rejectlist ? $rejectlist : [];
                    shuffle($surlist);
                    foreach ($surlist as $k => $v) {
                        $surfd = $v["fd"];


                        if (isset($rejectlist[$surfd])) {
                            continue;
                        }
                        $surinfo = self::getDeviceInfoByFd($surfd);
                        $call_status = $surinfo["call_status"];
                        if ($call_status == self::SUR_FREE) {


                            $rdata["code"] = 0;
                            $rdata["msg"] = "ok";
                            $rdata["data"]["cmd"] = "wait";
                            Base::pushJson($rdata, $robotfd); //wait


                            //问问监控同意不同意

                            self::changeDeviceCallStatus($surfd, self::SUR_USE);
                            $surdata["code"] = 0;
                            $surdata["msg"] = "ok";
                            $surdata["data"]["cmd"] = "callin";
                            $surdata["data"]["imei"] = $robotimei;
                            Base::pushJson($surdata, $surfd);
                            return;
                        }
                    }
                    //没有监控接
                    $rdata["code"] = 0;
                    $rdata["msg"] = "ok";
                    $rdata["data"]["cmd"] = "nosurfree";
                    Base::pushJson($rdata, $robotfd); //nosurfree
                    //修改机器人状态为等待

                    self::changeRobotCallStatusByImei($robotimei, self::ROBOT_WAIT);


                    //            $bsurdata["code"] = 0;
                    //            $bsurdata["msg"] = "ok";
                    //            $bsurdata["data"]["cmd"] = "notusestatus";
                    //            $bsurdata["data"]["imei"] = $robotimei;

                    //修改
                    self::changeDeviceCallStatus($robotfd, self::ROBOT_WAIT);
                    // self::broadcastsur($bsurdata);

                } else {
                    $rdata["code"] = 0;
                    $rdata["msg"] = "ok";
                    $rdata["data"]["cmd"] = "nosuronline";
                    Base::pushJson($rdata, $robotfd); //nosuronline
                }
            }
        }
    }

    public static function callrc($robotimei, $car_number, $passcode, $robot_id, $surfd)
    {


        //        $surfd = (int)$surfd;

        //        $passcodearr = ["zjzw", "pdqb", "qxxs"];
        //
        //        if (in_array($passcode, $passcodearr)) {
        //
        //            $passcode = "other";
        //        }


        //   $rcdata = "?2|{$robotimei}|{$car_number}|{$robot_id}|{$passcode}?";
        // callrc:fd:7f00000108fd000000a7_?2|PC210519320185Default string|287|4|hand?
        //   devlog("callrc:fd:{$surfd}_{$rcdata}");
        //   Base::pushJson($rcdata, $surfd);
    }

    public static function getSurFdByCoachId($coach_id)
    {


        $key = "getSurFdByCoachId:{$coach_id}";


        $surfd = Base::redisGet($key);

        return $surfd;
    }


    public static function addhandwarning($student_id)
    {
        $host = getenv("host");
        $url = "{$host}api/lsods/addhandwarning";
        $post["student_id"] = $student_id;
        Base::curlpost($url, $post);
    }

    public static function robotautocallsur($robotfd)
    {
        devlog("机器人 自动呼叫监控 robotfd：$robotfd ");

        $robotinfo = self::getDeviceInfoByFd($robotfd);
        $toastmsg = "自动呼叫:";
        if (!$robotinfo) {
            return;
        }
        $robotimei = $robotinfo["imei"];
        $car_number = $robotinfo["car_number"];

        $robotinfobyimei = self::getRobotInfoByImei($robotimei);
        if (!isset($robotinfobyimei["student_id"])) {

            $toastmsg = " {$car_number} 未登录呼叫失败";

            Base::toast($toastmsg);
            $rdata["code"] = 0;
            $rdata["msg"] = "ok";
            $rdata["data"]["cmd"] = "nosuronline";
            Base::pushJson($rdata, $robotfd); //nosuronline
        }

        $student_id = isset($robotinfobyimei["student_id"]) ? $robotinfobyimei["student_id"] : 0;


        $coachinfo = Base::getCoachByStudent($student_id);
        devlog("机器人自动呼叫监控coachinfo:");
        devlog($coachinfo);

        if ($coachinfo) {
            $coach_name = $robotinfo["coach_name"] = $coachinfo["coach_name"];
            $coach_id = $robotinfo["coach_id"] = $coachinfo["coach_id"];


            if ($coach_name && $coach_name != "未绑定") {

                $toastmsg = "{$toastmsg} {$car_number} 呼叫 {$coach_name}";

                Base::toast($toastmsg);
            }
        } else {
            $toastmsg = "{$toastmsg} {$car_number} 呼叫错误 无教练";

            Base::toast($toastmsg);
            return;
        }


        $surfd = self::getSurFdByCoachId($coach_id);
        //   self::devlog("机器人 呼叫监控 surfd：{$surfd}");

        if (!$surfd) {
            $rdata["code"] = 0;
            $rdata["msg"] = "ok";
            $rdata["data"]["cmd"] = "nosuronline";
            Base::pushJson($rdata, $robotfd); //nosuronline
        }
        $surinfo = self::getDeviceInfoByFd($surfd);
        if (!$surinfo) {
            return;
        }

        $call_status = isset($surinfo["call_status"]) ? $surinfo["call_status"] : self::SUR_FREE;
        if ($call_status == self::SUR_FREE) {

            //正常通话

            $rdata["code"] = 0;
            $rdata["msg"] = "ok";
            $rdata["data"]["cmd"] = "wait";
            Base::pushJson($rdata, $robotfd); //wait


            //问问监控同意不同意

            $surimei = $surinfo["imei"];

            self::changeDeviceCallStatus($surfd, self::SUR_USE);
            $surinfobyimei = Base::getSurinfoByImei($surimei); //$surinfobyimei["pid"];

            $surpid = $surinfobyimei["pid"];
            if ($surpid) {
                //远程控制
                //   $robot_id = $robotinfo["robot_id"];
                //  $rcdata = "?0|{$robotimei}|{$car_number}?";
                //    Base::pushJson($rcdata, $surfd);

                //    $rcdata = "?0|{$robot_id}|{$car_number}?";

                //todo 告诉远控刷新


            } else {
                $surdata["code"] = 0;
                $surdata["msg"] = "{$car_number}呼叫你";
                $surdata["data"]["cmd"] = "callin";
                $surdata["data"]["imei"] = $robotimei;
                Base::pushJson($surdata, $surfd); //callin

            }


            //         self::devlog("callin surfd:$surfd");


            return;
        } else {
            //监控占线

            //没有监控接
            $rdata["code"] = 0;
            $rdata["msg"] = "ok";
            $rdata["data"]["cmd"] = "nosurfree";
            Base::pushJson($rdata, $robotfd); //nosurfree
            //修改机器人状态为等待

            self::changeRobotCallStatusByImei($robotimei, self::ROBOT_WAIT);
            self::changeDeviceCallStatus($robotfd, self::ROBOT_WAIT);

            //开始累计未接来电

            //       $this->numberofmissedcalls($robotimei, $surfd);


            return;
        }
    }

    public static function addSoonError($client_id, $data)
    {


        $robotfd = $client_id;
        $robotinfo = self::getDeviceInfoByFd($robotfd);

        if (!$robotinfo) {
            self::disconnect($robotfd);

            return;
        }

        $robotimei = $robotinfo["imei"];


        $robotinfobyimei = self::getRobotInfoByImei($robotimei);

        $soonError_code = $data['soonError_code'];


        //     self::devlog("soonError_code:{$soonError_code}");
    }

    public static function addError($client_id, $data)
    {

        //  devlog("addError $client_id");
        $robotfd = $client_id;
        $robotinfo = self::getDeviceInfoByFd($robotfd);

        if (!$robotinfo) {
            devlog("norobotinfodisconnect  $client_id");

            self::disconnect($robotfd);

            return;
        }

        //
        $robotimei = $robotinfo["imei"];

        $robot_id = $robotinfo["robot_id"];

        $robotinfobyimei = self::getRobotInfoByImei($robotimei);
        $student_id = isset($robotinfobyimei["student_id"]) ? $robotinfobyimei["student_id"] : 0;
        $studentinfo = self::getStudentById($student_id);
        $student_name = $studentinfo ? $studentinfo["student_name"] : "";
        $errorCode = $data['error_code'];

        //  devlog($errorCode);

        $key = "passidbyimei:{$robotimei}";

        $passid = Base::redisGet($key);
        $addErrorTimeOutkey = "addErrorTimeOut:{$robotfd}:{$passid}:{$errorCode}";

        $value = Base::redisGet($addErrorTimeOutkey);

        if ($value) {

            //  devlog("$addErrorTimeOutkey|{$value}");

            //  devlog("2秒内犯同1个错误不重复显示  $client_id");

            //2秒内犯同1个错误不重复显示
            return;
        }

        $new3errcode = Base::redisGetArr('stuCarNewNumberErrorArr' . $robotimei);
        if (empty($new3errcode)) {
            $new3errcode = [];

            $new3errcode[] = ["errcode" => $errorCode, "student_name" => $student_name];
        } else {

            array_unshift($new3errcode, ["errcode" => $errorCode, "student_name" => $student_name]);
        }



        $new3errcode = array_slice($new3errcode, 0, 10);
        Base::redisSetArr('stuCarNewNumberErrorArr' . $robotimei, $new3errcode, 10800);

        $WrongJudgeArr = Base::getErrorList();
        $noalert = [];
        $WrongJudge = [];
        $point_code = 0;
        $passcode = "";
        foreach ($WrongJudgeArr as $key => $v) {
            $suralert = $v["suralert"];

            if ($suralert == 0) {
                $noalert[] = $v['code'];
            }
            $WrongJudge[$v['code']] = $v['point'];
            if ($v['code'] == $errorCode) {
                $point_code = $v["point_code"];
                $passcode = $v["passcode"];
            }
        }


        Base::redisSet($addErrorTimeOutkey, 1, 30);
        $errorCodeArr = [];
        foreach ($new3errcode as $k => $v) {
            $errid = $v["errcode"];
            $vstudent_name = $v["student_name"];
            if (!isset($WrongJudge[$errid])) {
                continue;
            }
            if (!empty($errid)) {
                $code3 = str_pad(substr($errid, 0, 3), 8, "0", STR_PAD_RIGHT);
                $code5 = str_pad(substr($errid, 0, 5), 8, "0", STR_PAD_RIGHT);
                $err3 = isset($WrongJudge[$code3]) ? $WrongJudge[$code3] : "未知项目:{$code3}"; //项目
                $err5 = isset($WrongJudge[$code5]) ? $WrongJudge[$code5] : ""; //阶段
                //         $err5 = isset($WrongJudge[$code5]) ? $WrongJudge[$code5] : "未知阶段:"; //阶段
                $err = isset($WrongJudge[$errid]) ? $WrongJudge[$errid] : "未知错误:{$errid}"; //错误
                // $errorCodeArr[] = '[' . $err3 . '] 一> ' . $err5 . ' :                              ' . $err;
                //   $errorCodeArr[] = "{$vstudent_name}[{$err3}]一>{$err5}:{$err}";
                $errorCodeArr[] = "{$vstudent_name}[{$err3}]|{$err5}:{$err}";
            }
        }
        $errorStr = isset($WrongJudge[$errorCode]) ? $WrongJudge[$errorCode] : "无效错误码:{$errorCode}";


        $errorStr = "{$student_name}:{$errorStr}";
        $rdata = [];
        $rdata["code"] = 0;
        $rdata["msg"] = "errorInfo";
        $rdata["data"]["cmd"] = "errorInfo";
        $rdata["data"]["errorCode"] = $errorCode;
        $rdata["data"]["errorStr"] = $errorStr;
        $rdata["data"]['error_list'] = $errorCodeArr;
        $rdata["data"]["imei"] = $robotimei;

        // devlog($rdata);

        self::broadcastsur($rdata);


        //clearerrnum 解除警报


        if (in_array($errorCode, $noalert)) {
            //     devlog("noalert  $client_id");

            //应该过滤掉
            return;
        }

        if (!$passcode) {
            $msg = "err no passcode({$errorCode})";

            // devlog($msg);
            Base::toast($msg);

            return;
        }
        //江苏路通 错一次 自动呼叫 TODO


        //        devlog("addErrorfinish $client_id");


    }

    public static function robot_alert($data)
    {


        $imei = $data["imei"];
        $msg = $data["msg"];
        Base::alert($msg, $imei);
    }

    public static function robot_toast($data)
    {
        $imei = $data["imei"];
        $msg = $data["msg"];

        Base::toast($msg, $imei);
    }

    public static function startpass($data)
    {

        //     devlog("startpass");
        //   self::devlog($data);

        $imei = $data["imei"];

        $student_id = $data["student_id"];

        if (!isset($data["code"])) {
            devlog("startpass no code");

            Base::toast("no code");

            return;
        }
        $code = $data["code"];
        $passname = self::getPassNameByCode($code);

        $student_name = self::getStudentNameById($student_id);
        $toastmsg = "{$student_name} 进入 {$passname}";
        //  MonitorLogic::toast($toastmsg);


        //学员清零犯错数量

        $key = "getstudenterrnum:{$student_id}";


        Redis::del($key);


        $key = "passidbyimei:{$imei}";

        $passid = Redis::incr($key);
        //   devlog("startpassfinish");


    }

    public static function getPassNameByCode($code)
    {
        $passname = [
            "dcrk" => "倒车入库",
            "pdqb" => "坡道起步",
            "cftc" => "侧方停车",
            "zjzw" => "直角转弯",
            "qxxs" => "曲线行驶",
        ];


        if (isset($passname[$code])) {
            $name = $passname[$code];
        } else {
            $name = "识别不到项目，机器人代码错误{$code}，请苗中振修复BUG";

            Base::toast("$name");
        }
        return $name;
    }

    public static function getStudentNameById($student_id)
    {

        $studentinfo = self::getStudentById($student_id);


        $student_name = $studentinfo ? $studentinfo["student_name"] : "未登录";
        return $student_name;
    }


    public static function endpass($data)
    {

        //   devlog("endpass");
        //    self::devlog($data);

        $imei = $data["imei"];

        $student_id = $data["student_id"];
        if (!isset($data["code"])) {
            devlog("endpass no code");

            Base::toast("no code");

            return;
        }
        $code = $data["code"];
        $passname = self::getPassNameByCode($code);

        $student_name = self::getStudentNameById($student_id);

        $toastmsg = "{$student_name} 退出关卡 {$passname}";
        //   MonitorLogic::toast($toastmsg);

        //   devlog("endpassfinish");

    }

    //不调了
    public static function rcconnect($client_id, $data)
    {
        $fd = $client_id;

        $ip = isset($data["ip"]) ? $data["ip"] : "";
        $imei = isset($data["imei"]) ? $data["imei"] : "";
        $imei = trim($imei);
        devlog("远控连接imei:{$imei} fd:{$fd}");
        //        $disconnect=isset($data["disconnect"])?$data["disconnect"]:0;
        //
        //        if($disconnect){
        //            devlog("远控 disconnect imei:{$imei} fd:{$fd} :{$disconnect}");
        //            self::disconnect($fd);
        //            return [];
        //        }

        if (!$imei) {
            devlog("no imei");
            return [];
        }
        $schoolwstoken = isset($data["schoolwstoken"]) ? $data["schoolwstoken"] : "";
        //    $surveillancelistkey = "surveillancelist";
        $rcsurveillancelistkey = "rcsurveillancelist";
        $rcsurveillancelist = self::getRCSurveillanceList();


        $localtoken = Base::gettoken();
        if ($localtoken != $schoolwstoken) {
            //  devlog("token error");
            self::disconnect($fd);
            return [];
        }
        $role = isset($data["role"]) ? $data["role"] : "";
        //        $rdata["code"] = 0;
        //        $rdata["msg"] = "connected";
        //        $rdata["data"]["cmd"] = "connected";


        // self::devlog(" surveillance connect fd:{$fd}");

        $surveillanceinfo["imei"] = $imei;
        $surveillanceinfo["ip"] = $ip;
        $surveillanceinfo["role"] = $role;
        $surveillanceinfo["fd"] = $fd;
        $surveillanceinfo["call_status"] = self::SUR_FREE;
        self::setDeviceInfoByFd($fd, $surveillanceinfo); //$surveillanceinfo
        $rcsurveillancelist[$imei] = $surveillanceinfo;

        Base::redisSetArr($rcsurveillancelistkey, $rcsurveillancelist, 3600 * 24);
        //远程控制

        self::setSurFdByCoachId($imei, $fd); //rcconnect 不调了


        return '';
    }

    public static function surveillanceheartbeat($client_id, $data)
    {
        $ip = isset($data["ip"]) ? $data["ip"] : "";
        $imei = isset($data["imei"]) ? $data["imei"] : "";

        $ts = isset($data["ts"]) ? $data["ts"] : 0;
        $reqid = isset($data["reqid"]) ? $data["reqid"] : 0;
        $now = time();
        $utime = "";
        if ($ts) {


            $utime = $now - $ts;
        }
        $imei = trim($imei);
        if ($imei) {
            //   $schoolwstoken = isset($data["schoolwstoken"]) ? $data["schoolwstoken"] : "";
            $surveillanceinfo["imei"] = $imei;
            $surveillanceinfo["ip"] = $ip;
            $surveillanceinfo["role"] = "surveillance";
            $surveillanceinfo["fd"] = $client_id;
            $surveillanceinfo["call_status"] = self::SUR_FREE;
            self::setDeviceInfoByFd($client_id, $surveillanceinfo); //surveillanceheartbeat
            $surveillancelist[$imei] = $surveillanceinfo;

            //远程控制


        }


        $msg = "receive heartbeat";

        $rdata["code"] = 0;
        $rdata["msg"] = $msg;
        $rdata["data"]["cmd"] = "heartbeat";

        $rdata["data"]["sendts"] = $ts;
        $rdata["data"]["receivets"] = $now;
        $rdata["data"]["reqid"] = $reqid;
        $rdata["data"]["utime"] = $utime;
        $rdata["data"]["msgid"] = 0;


        Base::pushJson($rdata, $client_id);
    }

    //监控呼叫机器人
    public static function callrobot($client_id, $data)
    {
        //修改机器人状态
        //todo  有BUG

        $surfd = $client_id;
        $robotimei = $data["imei"];
        //  Base::toasttofd($surfd,"监控呼叫机器人");

        //     devlog("robotimei：{$robotimei} callrobot"); // 运行到此

        if (!$robotimei) {
            devlog("未选择车辆");
            Base::toasttofd($surfd, "__________________监控呼叫机器人未选择车辆");

            $surdata["code"] = 10023;
            $surdata["msg"] = "未选择车辆";
            $surdata["data"]["cmd"] = "error";
            Base::pushJson($surdata, $surfd);

            return;
        }

        // todo 判断监控状态
        $surdeviceinfo = self::getDeviceInfoByFd($surfd);
        //todo 发现 $surdeviceinfo 存在 false的情况
        $surcall_status = isset($surdeviceinfo["call_status"]) ? $surdeviceinfo["call_status"] : "";

        if ($surcall_status !== "") {


            //            if ($surcall_status == self::SUR_USE) {
            //
            //
            //                self::devlog("你正在通话");
            //                $surdata["code"] = 10024;
            //                $surdata["msg"] = "你正在通话";
            //                $surdata["data"]["cmd"] = "error";
            //                self::pushJson($surdata, $surfd);
            //
            //                return;
            //            }
        } else {
            devlog("监控呼叫机器人sur no call_status");
        }

        $robotimei = trim($robotimei);
        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);


        $student_id = isset($robotinfo["student_id"]) ? $robotinfo["student_id"] : 0;
        $robotfd = isset($robotinfo["fd"]) ? $robotinfo["fd"] : 0;


        if ($robotfd) {
            /// devlog("robotfd {$robotfd}");// 运行到此

            $robot_call_status = $robotinfo["call_status"];

            if ($robot_call_status == self::ROBOT_FREE || $robot_call_status == self::ROBOT_WAIT) {

                //  devlog("监控（{$surfd}）准备呼叫机器人{$robotfd} "); //

                //     self::clearnumberofmissedcalls($robotimei, $surfd);

                //   devlog("clearnumberofmissedcalls ok"); //

                self::changeDeviceCallStatus($surfd, self::SUR_USE);
                $surip = $surdeviceinfo["ip"];
                //   devlog("change sur CallStatus ok"); //
                $car_number = $robotinfo["car_number"];

                Base::toasttofd($surfd, "监控呼叫机器人({$car_number})成功");

                //如果机器人在空闲或者等待状态 变更机器人呼叫状态为 使用中


                if (!isset($surdeviceinfo["imei"])) {
                    devlog("no imei");

                    Base::errlog("no imei");
                    Base::errlog(json_encode($surdeviceinfo, JSON_UNESCAPED_UNICODE));
                }

                $surimei = $surdeviceinfo["imei"];
                ///   self::devlog("{$robotimei}变更机器人呼叫状态为使用中");

                self::changeDeviceCallStatus($robotfd, self::ROBOT_USR, $surimei);
                // devlog("change robot CallStatus ok"); //

                //服务器给机器人发送监控的IP

                $rdata["code"] = 0;
                $rdata["msg"] = "$car_number";
                $rdata["data"]["cmd"] = "surcallin";
                $rdata["data"]["surip"] = $surip;

                $pj = Base::pushJson($rdata, $robotfd); //surcallin
                devlog("surcallin监控呼叫机器人({$car_number}:{$robotfd})成功::push_return:{$pj}"); //可能没允许到此
                // devlog($pj);

                //记录当前监控与哪辆车通话


                $callstatusrobotfdbysurfdkey = "callstatusrobotfdbysurfd:{$surfd}";


                Base::redisSet($callstatusrobotfdbysurfdkey, $robotfd, 3600);
                //记录数据库 接听 robot_warning todo 获取 $student_id

                if ($student_id) {
                    //     self::answerwarning($student_id);
                }
                //

                $callkey = "call:robot:{$robotimei}";


                $rcid = Base::redisGet($callkey);
                if ($rcid) {
                    //   self::startrobotcall($student_id, $robotinfo, $coach_id);
                    self::answercall($rcid);
                }
            } else {
                devlog("机器人占线状态");

                //机器人占线状态
                Base::toasttofd($surfd, "__________________监控呼叫机器人机器人占线状态");


                $surdata["code"] = 10024;
                $surdata["msg"] = "占线";
                $surdata["data"]["cmd"] = "error";
                Base::pushJson($surdata, $surfd);
            }
        } else {
            Base::toasttofd($surfd, "__________________监控呼叫机器人机器人{$robotimei}离线");

            devlog("机器人{$robotimei}离线");

            $surdata["code"] = 10023;
            $surdata["msg"] = "机器人离线";
            $surdata["data"]["cmd"] = "error";
            Base::pushJson($surdata, $surfd);
        }
        //解除警报

        // self::clearerrnum($robotimei);


    }

    public static function endrobotcall($robotinfo)
    {
        $robot_id = $robotinfo["robot_id"];
        devlog("endrobotcall:robot_id:{$robot_id}");
        $key = "getstartrobotcall:rcid:{$robot_id}";
        $rcid = Base::redisGet($key);
        devlog("endrobotcall:rcid:{$rcid}");

        if ($rcid) {
            $host = getenv("host");
            $url = "{$host}api/lsods/endrobotcall";
            $post["rcid"] = $rcid;
            Base::curlpost($url, $post);
        }
    }

    public static function answercall($rcid)
    {
        $host = getenv("host");

        $url = "{$host}api/lsods/answercall";
        $post["rcid"] = $rcid;

        Base::curlpost($url, $post);
    }

    public static function startrobotcall($student_id, $robotinfo, $coach_id)
    {


        $robot_id = $robotinfo["robot_id"];

        $host = getenv("host");
        $url = "{$host}api/lsods/startrobotcall";
        $post["student_id"] = $student_id;
        $post["robot_id"] = $robot_id;
        $post["coach_id"] = $coach_id;
        $rt = Base::curlpost($url, $post);
        if ($rt["code"] == 0) {

            $rcid = $rt["data"]["rcid"];
            $robotimei = $robotinfo["imei"];
            $callkey = "call:robot:{$robotimei}";
            Base::redisSet($callkey, $rcid, 29);
            $key = "getstartrobotcall:rcid:{$robot_id}";
            Base::redisSet($key, $rcid, 3600);
        }
    }

    public static function clearnumberofmissedcalls($robotimei, $surfd)
    {

        //    devlog("clearnumberofmissedcalls");
        //清除未接来电
        $numberofmissedcallskey = "numberofmissedcalls:{$robotimei}";
        Redis::del($numberofmissedcallskey);
        //      devlog("del clearnumberofmissedcalls ");

        $surdata["code"] = 0;
        $surdata["msg"] = "ok";
        $surdata["data"]["cmd"] = "numofmissedcalls";
        $surdata["data"]["imei"] = $robotimei;
        $surdata["data"]["nomc"] = 0;
        //    $rcdata = "?1|{$robotimei}|0?";
        // devlog(" clearnumberofmissedcalls pushJson 1");

        //     Base::pushJson($rcdata, $surfd);

        //   devlog(" clearnumberofmissedcalls pushJson 2");

        //解除警报
        $md = date("md");

        //   devlog("clearnumberofmissedcalls $md");

        $passid = self::getpassidbyimei($robotimei);
        $errbyimeikey = "errbyimei:{$md}:{$robotimei}:{$passid}";
        $now = time();
        $errtime = Base::redisGet($errbyimeikey);
        if (!$errtime) {
            return;
        }
        //判断是否在5分钟内
        if (($now - $errtime) < 60 * 5) {
            Redis::del($errbyimeikey); //解除这个报警
            $keys = "errbyimei:{$md}:{$robotimei}:*";
            $list = Redis::keys($keys);
            $errnum = count($list); //报警数量
            $backcolor = "green";
            self::syncerrnum($errnum, $backcolor, $robotimei);
        }

        //  devlog("clearnumberofmissedcalls over");

    }

    public static function getpassidbyimei($imei)
    {
        $key = "passidbyimei:{$imei}";

        $passid = Base::redisGet($key);

        return $passid;
    }

    public static function syncerrnum($errnum, $backcolor, $robotimei)
    {

        $robotinfo = self::getRobotInfoByImei($robotimei);
        $robotinfo["errnum"] = $errnum;
        //  self::setRobotInfoByImei($robotimei, $robotinfo);//syncerrnum
        $rdata["code"] = 0;
        $rdata["msg"] = "";
        $rdata["data"]["cmd"] = "syncerrnum";
        $rdata["data"]["errnum"] = $errnum;
        $rdata["data"]["backcolor"] = $backcolor;
        $rdata["data"]["imei"] = $robotimei;
        self::broadcastsur($rdata);
    }

    public static function surreject($client_id, $data)
    {
        $surfd = $client_id;
        //变更机器人呼叫状态 空闲

        $toastmsg = "监控拒绝机器人通话";

        Base::toast($toastmsg);

        self::changeDeviceCallStatus($surfd, self::SUR_FREE);
        $robotimei = $data["imei"];
        $robotimei = trim($robotimei);

        $rejectlistbyimeikey = "rejectlistbyimei::{$robotimei}";
        $rejectlist = Base::redisGetArr($rejectlistbyimeikey);
        $now = time();
        if ($rejectlist) {
            foreach ($rejectlist as $k => $v) {
                if ($v + 30 < $now) {
                    unset($rejectlist[$k]);
                }
            }
        }
        $rejectlist[$surfd] = $now;
        Base::redisSetArr($rejectlistbyimeikey, $rejectlist, 30);
        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);
        if (!isset($robotinfo["fd"])) {
            //这里会报错 需要查查原因
            //   self::devlog("监控拒绝机器人{$robotimei}通话 查不到fd");
            //   self::devlog($robotinfo);
        }
        $robotfd = $robotinfo["fd"];
        self::robotCallSurveillance($robotfd);
    }

    public static function surcoachreject($client_id, $data)
    {

        devlog("surcoachreject");

        $surfd = $client_id;

        $surinfo = self::getDeviceInfoByFd($surfd);


        //变更机器人呼叫状态 空闲


        self::changeDeviceCallStatus($surfd, self::SUR_FREE);
        $robotimei = $data["imei"];

        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);

        if (!$robotinfo) {
            $toastmsg = "监控拒绝通话(找不到机器人#{$robotimei}#)";

            Base::toast($toastmsg);
            return;
        }
        $robotfd = isset($robotinfo["fd"]) ? $robotinfo["fd"] : "";

        if ($robotfd) {
            self::changeDeviceCallStatus($robotfd, self::ROBOT_FREE);
            $rdata["code"] = 0;
            $rdata["msg"] = "endcall";
            $rdata["data"]["cmd"] = "endcall";
            Base::pushJson($rdata, $robotfd); //endcall
            //   $this->numberofmissedcalls($robotimei, $surfd);

            self::endrobotcall($robotinfo);
        }
    }

    public static function hangup($client_id, $data)
    {
        $surfd = $client_id;

        devlog("hangup");

        self::changeDeviceCallStatus($surfd, self::SUR_FREE);

        $robotimei = $data["imei"];
        $robotimei = trim($robotimei);
        //self::devlog("{$robotimei} hangup");

        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);
        if ($robotinfo) {

            $robotfd = isset($robotinfo["fd"]) ? $robotinfo["fd"] : 0;
            if ($robotfd) {
                //判断这个机器人是不是和这个监控在连接
                $robotinfo = Base::getRobotCoachinfoByImei($robotimei);
                $robot_call_status = $robotinfo["call_status"];

                if ($robot_call_status != self::ROBOT_USR) {
                    devlog("{$robotimei} 机器人不在使用状态");

                    $surdata["code"] = 10023;
                    $surdata["msg"] = "robotcallnouse 机器人未通话 不需要挂断";
                    $surdata["data"]["cmd"] = "error";
                    Base::pushJson($surdata, $surfd);

                    return;
                }

                $robotfdinfo = self::getDeviceInfoByFd($robotfd);
                if (!$robotfdinfo) {

                    $surdata["code"] = 10023;
                    $surdata["msg"] = "机器人离线";

                    $surdata["data"]["cmd"] = "error";

                    Base::pushJson($surdata, $surfd);

                    return;
                }


                if (!isset($robotfdinfo["surimei"])) {
                    devlog("{$robotimei} 机器人没有连接1653");

                    $surdata["code"] = 10023;
                    $surdata["msg"] = "机器人没有连接1656";
                    $surdata["data"]["cmd"] = "error";
                    Base::pushJson($surdata, $surfd);

                    return;
                }
                //surimei 机器人的监控 在通话时建立关系
                $surimei = isset($robotfdinfo["surimei"]) ? $robotfdinfo["surimei"] : "";

                if (!$surimei) {

                    $surdata["code"] = 10023;
                    $surdata["msg"] = "机器人没有连接1668";
                    $surdata["data"]["cmd"] = "error";
                    Base::pushJson($surdata, $surfd);
                    return;
                }

                $surinfo = self::getDeviceInfoByFd($surfd);

                $surredisimei = $surinfo["imei"];

                if ($surimei != $surredisimei) {
                    $surdata["code"] = 10023;
                    $surdata["msg"] = "其他监控连接中";
                    $surdata["data"]["cmd"] = "error";
                    Base::pushJson($surdata, $surfd);

                    return;
                }


                //变更机器人呼叫状态 空闲
                self::changeDeviceCallStatus($robotfd, self::ROBOT_FREE);
                $rdata["code"] = 0;
                $rdata["msg"] = "endcall";
                $rdata["data"]["cmd"] = "endcall";
                Base::pushJson($rdata, $robotfd); //endcall


                $callstatusrobotfdbysurfdkey = "callstatusrobotfdbysurfd:{$surfd}";

                Redis::del($callstatusrobotfdbysurfdkey);


                self::endrobotcall($robotfdinfo);
            } else {

                $surdata["code"] = 10023;
                $surdata["msg"] = "机器人离线";
                $surdata["data"]["cmd"] = "error";
                Base::pushJson($surdata, $surfd);
            }
        } else {
            $surdata["code"] = 0;
            $surdata["msg"] = "no robot";
            $surdata["data"]["cmd"] = "error";
            Base::pushJson($surdata, $surfd);
        }
    }


    public static function brake($client_id, $data)
    {
        $robotimei = $data["imei"];


        if (!$robotimei) {
            $surfd = $client_id;
            $surdata["code"] = 10023;
            $surdata["msg"] = "未选择车辆";
            $surdata["data"]["cmd"] = "error";
            Base::pushJson($surdata, $surfd);

            return;
        }

        $robotimei = trim($robotimei);

        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);

        $robotfd = isset($robotinfo["fd"]) ? $robotinfo["fd"] : 0;


        $rdata["code"] = 0;
        $rdata["msg"] = "brake";
        $rdata["data"]["cmd"] = "brake";
        //        $rtjson = json_encode($rdata);
        Base::pushJson($rdata, $robotfd); //brake


    }

    public static function stopbrake($data)
    {
        $robotimei = $data["imei"];
        $robotimei = trim($robotimei);

        $robotinfo = Base::getRobotCoachinfoByImei($robotimei);
        if ($robotinfo) {

            $robotfd = isset($robotinfo["fd"]) ? $robotinfo["fd"] : 0;

            //$brakekey = "brakebyimei:{$robotimei}";
            // Redis::del($brakekey);

            $rdata["code"] = 0;
            $rdata["msg"] = "stopbrake";
            $rdata["data"]["cmd"] = "stopbrake";

            Base::pushJson($rdata, $robotfd); //stopbrake

        }
    }

    public static function surChangeCallStatus($fd, $data)
    {

        //   devlog("监控发送命令 surChangeCallStatus");
        $call_status = $data["call_status"];
        self::changeDeviceCallStatus($fd, $call_status);
    }

    public static function onClose($client_id)
    {
        $deviceinfo = self::getDeviceInfoByFd($client_id);

        //   devlog("onClose {$client_id}：" . json_encode($deviceinfo, JSON_UNESCAPED_UNICODE));

    }

    public static function getSurveillanceList()
    {
        $surveillancelistkey = "surveillancelist";
        $surveillancelist = Base::redisGetArr($surveillancelistkey);

        return $surveillancelist;
    }

    public static function getRCSurveillanceList()
    {
        $surveillancelistkey = "rcsurveillancelist";
        $surveillancelist = Base::redisGetArr($surveillancelistkey);

        return $surveillancelist;
    }

    public static function disconnect($fd)
    {


        $rdata["code"] = 10020;
        $rdata["msg"] = "token errro";
        $rdata["data"]["cmd"] = "DISCONNECTED";
        Base::pushJson($rdata, $fd); //disconnect


        Gateway::closeClient($fd);


        self::remdevice($fd);
    }

    public static function getDeviceInfoByFd($fd)
    {
        $fdkey = "deviceinfobyfd:{$fd}";

        $deviceinfo = Base::redisGetArr($fdkey);

        return $deviceinfo;
    }


    public static function setDeviceInfoByFd($fd, $deviceinfo)
    {
        $fdkey = "deviceinfobyfd:{$fd}";
        Base::redisSetArr($fdkey, $deviceinfo, 3600 * 24);
    }


    public static function changeDeviceCallStatus($fd, $call_status, $surimei = "")
    {
        $deviceinfo = self::getDeviceInfoByFd($fd);

        if (!$deviceinfo) {
            return;
        }
        $deviceinfo["call_status"] = $call_status;
        if ($surimei) {
            $deviceinfo["surimei"] = $surimei;
        }


        self::setDeviceInfoByFd($fd, $deviceinfo); //changeDeviceCallStatus


        if (!$deviceinfo) {

            //            $rdata = [
            //                "code" => 0,
            //                "msg" => "no deviceinfo",
            //                "data" => [
            //                    "cmd" => "error"
            //                ]
            //            ];
            //            Base::pushJson($rdata, $fd);//error
            $toastmsg = "changeDeviceCallStatus {$call_status} no deviceinfo";

            Base::toast($toastmsg);
        }
        if (!isset($deviceinfo["role"])) {
            return;
        }


        if ($deviceinfo["role"] == self::ROLE_ROBOT || $deviceinfo["role"] == self::ROLE_sub3robot) {

            if (!$deviceinfo["imei"]) {


                return;
            }
            $imei = $deviceinfo["imei"];
            self::changeRobotCallStatusByImei($imei, $call_status);
            $rdata["code"] = 0;
            $rdata["msg"] = "ok";
            $rdata["data"]["cmd"] = "changeRobotCallStatus";
            $rdata["data"]["imei"] = $imei;
            $rdata["data"]["call_status"] = $call_status;
            Base::broadcastsur($rdata);
        }
    }

    public static function changeRobotCallStatusByImei($robotimei, $call_status)
    {
        $robotinfo = self::getRobotInfoByImei($robotimei);

        $robotinfo["call_status"] = $call_status;
        self::setRobotInfoByImei($robotimei, $robotinfo); //changeRobotCallStatusByImei

    }

    public static function broadcastsub3robot($rdata, $client_id)
    {
        $surdata["msg"] = "ok";
        $surdata["code"] = 0;
        $surdata["data"] = $rdata;
        $surdata["data"]["cmd"] = "robot3sync";


        $robotheartbeaimeitkey = "robot3heartbeatimei:*";

        $robotheartbeatlist = Redis::keys($robotheartbeaimeitkey);

        if ($robotheartbeatlist) {

            foreach ($robotheartbeatlist as $v) {
                $robotheartbeat = trim($v, "swoft:");
                $fdarr = explode(":", $robotheartbeat);
                $imei = $fdarr[1];
                $deviceinfo = self::getSub3RobotInfoByImei($imei);

                if ($deviceinfo) {
                    //  $car_number = $deviceinfo["car_number"];

                    //  $robot_id = $deviceinfo["robot_id"];
                    $fd = $deviceinfo["fd"];

                    if ($fd != $client_id) {

                        Base::pushJson($surdata, $fd);
                    }
                }
            }
        } else {
            devlog("broadcastsub3robot no car");
        }
    }

    public static function broadcastsur($rdata)
    {
        $cmd = $rdata["data"]["cmd"];
        $surveillancelistkey = "surveillancelist";
        $surveillancelist = Base::redisGetArr($surveillancelistkey);
        if ($surveillancelist) {
            foreach ($surveillancelist as $surveillanceinfo) {
                $surveillancefd = $surveillanceinfo["fd"];


                if (!isset($rdata["data"]["msgid"])) {
                    $key = "broadcastsurid:{$cmd}:{$surveillancefd}";

                    $broadcastsurid = Base::redisIncr($key);
                    $rdata["data"]["msgid"] = $broadcastsurid;
                }
                Base::pushJson($rdata, $surveillancefd);
            }
        }
    }

    public static function remdevice($fd)
    {

        $fdkey = "deviceinfobyfd:{$fd}";

        $deviceinfo = self::getDeviceInfoByFd($fd);

        if ($deviceinfo) {
            Redis::del($fdkey);
            $imei = $deviceinfo["imei"];
            $role = $deviceinfo["role"];
            if ($role == "robot_coach") {
                $md = date("md");
                $robotheartbeaimeitkey = "robotheartbeatimei:{$imei}";
                Redis::del($robotheartbeaimeitkey);
                $loginkey = "userloginbyimei:{$md}:{$imei}";

                Redis::del($loginkey);
                $robotkey = "robotinfo:{$imei}";

                unset($deviceinfo["fd"]);
                unset($deviceinfo["ip"]);
                unset($deviceinfo["status"]);


                Base::redisSetArr($robotkey, $deviceinfo);
                $surdata["code"] = 0;
                $surdata["msg"] = "";
                $surdata["data"]["cmd"] = "robotstatus";
                $surdata["data"]["status"] = 0;
                $surdata["data"]["imei"] = $imei;
                $surdata["data"]["robot_id"] = $deviceinfo["robot_id"];
                $surdata["data"]["car_number"] = $deviceinfo["car_number"];


                Base::broadcastsur($surdata);


                //机器人下线修改状态
                self::changeRobotStatus(self::ROBOT_OFFLINE, $imei); //remdevice
                // self::clearerrnum($imei);


            } elseif ($role == "surveillance") {
                //检查一下有没有正在通话的机器人

                $callstatusrobotfdbysurfdkey = "callstatusrobotfdbysurfd:{$fd}";

                $robotfd = Base::redisGet($callstatusrobotfdbysurfdkey);

                if ($robotfd) {
                    self::changeDeviceCallStatus($robotfd, self::ROBOT_FREE);
                }


                $surveillancelistkey = "surveillancelist";

                $surveillancelist = Base::redisGetArr($surveillancelistkey);
                if (isset($surveillancelist[$imei])) {
                    unset($surveillancelist[$imei]);

                    Base::redisSetArr($surveillancelistkey, $surveillancelist, 3600 * 24);
                }
            }
        }
    }

    public static function getSub3RobotInfoByImei($imei)
    {
        $robotkey = "sub3robotinfo:{$imei}";
        $robotinfo = Base::redisGetArr($robotkey);

        return $robotinfo;
    }

    public static function getRobotInfoByImei($imei)
    {
        $robotkey = "robotinfo:{$imei}";
        $robotinfo = Base::redisGetArr($robotkey);

        return $robotinfo;
    }

    public static function changeRobotStatus($status, $imei)
    {

        $robotinfo = self::getRobotInfoByImei($imei);
        if ($robotinfo) {
            $robotinfo["status"] = $status;

            self::setRobotInfoByImei($imei, $robotinfo); //changeRobotStatus
        }
    }

    public static function changeSub3RobotStatus($status, $imei)
    {

        $robotinfo = self::getSub3RobotInfoByImei($imei);
        if ($robotinfo) {
            $robotinfo["status"] = $status;

            self::setRobotInfoByImei($imei, $robotinfo); //changeRobotStatus
            self::setSub3RobotInfoByImei($imei, $robotinfo); //changeRobotStatus
        }
    }

    public static function setRobotInfoByImei($imei, $robotinfo)
    {
        $robotkey = "robotinfo:{$imei}";
        Base::redisSetArr($robotkey, $robotinfo);
    }

    //setSub3RobotInfoByImei
    public static function setSub3RobotInfoByImei($imei, $robotinfo)
    {
        $robotkey = "sub3robotinfo:{$imei}";
        Base::redisSetArr($robotkey, $robotinfo);
    }

    public static function getmastersurip()
    {
        $mastersurip = "setmastersurip";
        $mastersurip = Base::redisGet($mastersurip);


        return $mastersurip;
    }

    public static function setmastersurip($ip)
    {
        $mastersurip = "setmastersurip";
        $surveillancelist = Base::redisSet($mastersurip, $ip);
    }

    public static function sendmasteriptorobotlist($surip)
    {
        $robotlist = Base::getrobotlist();
        foreach ($robotlist as $k => $v) {

            $fd = isset($v["fd"]) ? $v["fd"] : "";
            if ($fd) {



                $rdata["code"] = 0;
                $rdata["msg"] = "masterstart";
                $rdata["data"]["cmd"] = "masterstart";
                $rdata["data"]["surip"] = $surip;
                $rdata["data"]["msgid"] = 0;
                Base::pushJson($rdata, $fd); //initrobotlist

            }
        }
    }
    public static function connect($client_id, $data)
    {
        //   self::devlog("connect");

        $fd = $client_id;
        //滕飞在获取IP经常犯错 需要注意
        $ip = isset($data["ip"]) ? $data["ip"] : "";
        $imei = isset($data["imei"]) ? $data["imei"] : "";
        $imei = trim($imei);
        if (!$imei) {
            devlog("no imei");
            return [];
        }
        // $imei = trim($imei, "LKY");
        $type = isset($data["type"]) ? $data["type"] : 1;

        $schoolwstoken = isset($data["schoolwstoken"]) ? $data["schoolwstoken"] : "";

        $localtoken = Base::gettoken();
        if ($localtoken != $schoolwstoken) {
            devlog("token error lds:{$localtoken} != {$schoolwstoken}");


            self::disconnect($fd);
            return [];
        }
        $role = isset($data["role"]) ? $data["role"] : "";

        if ($role == "sub3robot") {
            //      $role = "robot_coach";
        }
        $time = time();

        if ($role == "robot_coach") {

            //   devlog("robot_coach {$imei} connect fd:{$fd}");
            $robotheartbeaimeitkey = "robotheartbeatimei:{$imei}";
            Base::redisSet($robotheartbeaimeitkey, $time, 600);
            $robotinfo = Base::getRobotCoachinfoByImei($imei, $type);
            $robot_id = $robotinfo["robot_id"];
            if (!$robotinfo) {
                Base::toast("imei错误：{$imei}");
                self::disconnect($fd);
            }
            if (!isset($robotinfo["coach_id"])) {
                devlog("连接 no coach_id");
            }
            if (!$robotinfo) {
                $rdata["code"] = 10020;
                $rdata["msg"] = "robot error";
                $rdata["data"]["cmd"] = "DISCONNECTED";

                devlog("robot error");
                Base::pushJson($rdata, $fd); //DISCONNECTED
                return [];
            }
            $robotinfo["ip"] = $ip;
            $robotinfo["fd"] = $fd;
            $robotinfo["subject"] = 2;
            $robotinfo["role"] = $role;
            $robotinfo["status"] = self::ROBOT_ONLINE; //todo 把已登录改为已连接
            $robotinfo["name"] = "";
            $robotinfo["call_status"] = self::ROBOT_FREE;
            $robotinfo["robot_id"] = $robot_id;

            $car_number = $robotinfo["car_number"];
            //     devlog("robot_coach {$imei} connect fd:{$fd} {$car_number}");

            self::setDeviceInfoByFd($fd, $robotinfo); //connectROBOT
            $robotkey = "robotinfo:{$imei}";
            Base::redisSetArr($robotkey, $robotinfo);

            //修改机器人状态


            self::changeRobotStatus(self::ROBOT_ONLINE, $imei); //connect



            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "robotstatus";
            $surdata["data"]["status"] = 1;
            $surdata["data"]["imei"] = $robotinfo["imei"];
            $surdata["data"]["car_number"] = $robotinfo["car_number"];
            $surdata["data"]["ip"] = $ip;
            $surdata["data"]["robot_id"] = $robot_id;



            Base::broadcastsur($surdata);


            $toastmsg = "{$car_number}上线";

            Base::toast($toastmsg);
        } elseif ($role == "surveillance") {
            $master = isset($data["master"]) ? $data["master"] : 0;
            if ($master) {
                self::setmastersurip($ip);
                //推送给所有学员端


                self::sendmasteriptorobotlist($ip);
            }


            //  $subject= isset($data["subject"]) ? $data["subject"] : 2;
            $surveillancelistkey = "surveillancelist";
            $robotlist = Base::getrobotlist();
            $surveillancelist = self::getSurveillanceList();
            Base::toasttofd($fd, "当前监控{$imei}连接到LDS{$fd}");
            devlog("监控 {$imei} surveillanceconnect fd:{$fd}");
            $surveillanceinfo["imei"] = $imei;
            $surveillanceinfo["ip"] = $ip;
            $surveillanceinfo["role"] = $role;
            $surveillanceinfo["fd"] = $fd;
            $surveillanceinfo["call_status"] = self::SUR_FREE;
            self::setDeviceInfoByFd($fd, $surveillanceinfo); //connect surveillance
            $surveillancelist[$imei] = $surveillanceinfo;
            Base::redisSetArr($surveillancelistkey, $surveillancelist, 3600 * 24);
            self::setSurFdByCoachId($imei, $fd); //connect

            $rdata["code"] = 0;
            $rdata["msg"] = "";
            $rdata["data"]["cmd"] = "initrobotlist"; //connect
            $rdata["data"]["robotinfolist"] = $robotlist;
            $rdata["data"]["fd"] = $fd;
            $school_id = getenv("school_id");
            $rdata["data"]["schoolinfo"]["school_id"] = $school_id;




            if (!$robotlist) {
                $rdata["code"] = -1;
                $rdata["msg"] = "没有车辆在线";
            }

            devlog($rdata);
            Base::pushJson($rdata, $fd); //DISCONNECTED
            $surinfo = Base::getSurinfoByImei($imei); //connect $surinfo["pid"]
            $pid = isset($surinfo["pid"]) ? $surinfo["pid"] : 0;
            if ($pid) {
                devlog("远控连接imei:{$imei} fd:{$fd}");
                $rcsurveillancelistkey = "rcsurveillancelist";
                $rcsurveillancelist = self::getRCSurveillanceList(); //远控连接imei
                $surveillanceinfo["imei"] = $imei;
                $surveillanceinfo["ip"] = $ip;
                $surveillanceinfo["role"] = $role;
                $surveillanceinfo["fd"] = $fd;
                $surveillanceinfo["call_status"] = self::SUR_FREE;

                $rcsurveillancelist[$imei] = $surveillanceinfo;

                Base::redisSetArr($rcsurveillancelistkey, $rcsurveillancelist, 3600 * 24);

                $rcsurveillancelist = self::getRCSurveillanceList();
            }
        } elseif ($role == "sub3robot") {
            devlog("sub3robot {$imei} connect fd:{$fd}");
            $robotinfo = Base::getSub3RobotinfoByImei($imei);
            $robotheartbeaimeitkey = "sub3robotheartbeatimei:{$imei}";
            Base::redisSet($robotheartbeaimeitkey, $time, 600);
            $robot_id = $robotinfo["robot_id"];
            if (!$robotinfo) {
                Base::toast("imei错误：{$imei}");
                self::disconnect($fd);
            }

            if (!$robotinfo) {
                $rdata["code"] = 10020;
                $rdata["msg"] = "robot error";
                $rdata["data"]["cmd"] = "DISCONNECTED";

                devlog("robot error");
                Base::pushJson($rdata, $fd); //DISCONNECTED
                return [];
            }
            $surveillancelistkey = "surveillancelist";
            $surveillancelist = Base::redisGetArr($surveillancelistkey);

            $robotinfo["ip"] = $ip;
            $robotinfo["fd"] = $fd;
            $robotinfo["role"] = $role;
            $robotinfo["status"] = self::ROBOT_ONLINE; //todo 把已登录改为已连接
            $robotinfo["name"] = "";
            $robotinfo["subject"] = 3;
            $robotinfo["call_status"] = self::ROBOT_FREE;
            $robotinfo["robot_id"] = $robot_id;

            $car_number = $robotinfo["car_number"];
            devlog("sub3robot {$imei} connect fd:{$fd} {$car_number}");

            self::setDeviceInfoByFd($fd, $robotinfo); //connectsub3ROBOT
            $robotkey = "sub3robotinfo:{$imei}";
            Base::redisSetArr($robotkey, $robotinfo);
            $robotkey = "robotinfo:{$imei}";
            Base::redisSetArr($robotkey, $robotinfo);
            //修改机器人状态
            $robotheartbeaimeitkey = "robot3heartbeatimei:{$imei}";
            Base::redisSet($robotheartbeaimeitkey, $time, 600);
            self::changeSub3RobotStatus(self::ROBOT_ONLINE, $imei); //connect
            $surdata["code"] = 0;
            $surdata["msg"] = "";
            $surdata["data"]["cmd"] = "robotstatus";
            $surdata["data"]["status"] = 1;
            $surdata["data"]["imei"] = $robotinfo["imei"];
            $surdata["data"]["car_number"] = $robotinfo["car_number"];
            $surdata["data"]["ip"] = $ip;
            $surdata["data"]["robot_id"] = $robot_id;

            Base::broadcastsub3sur($surdata);

            $toastmsg = "{$car_number}上线";

            Base::toast($toastmsg);
        }
        $surip = self::getmastersurip();
        $rdata["data"]["surip"] = $surip;


        $rdata["code"] = 0;
        $rdata["msg"] = "connected";
        $rdata["data"]["cmd"] = "connected";
        $rdata["data"]["msgid"] = 0;
        Base::pushJson($rdata, $fd); //initrobotlist

        return '';
    }

    public static function setSurFdByCoachId($surimei, $surfd)
    {

        $pos = strpos($surimei, "_bottom");
        if ($pos !== false) {
            //网页版 过滤掉
            return;
        }
        $pos = strpos($surimei, "_web");

        if ($pos !== false) {

            //网页版 过滤掉
            return;
        }
        $surinfo = Base::getSurinfoByImei($surimei, true); //setSurFdByCoachId
        if (!$surinfo) {

            devlog("surimei({$surimei})获取不到教练端数据");
            Base::toast("surimei({$surimei})获取不到教练端数据");
            return;
        }


        // todo 判断类型为远程控制则写入redis


        $pid = isset($surinfo["pid"]) ? $surinfo["pid"] : 0;


        if ($pid) {
            //   return;
        }
        $coach_id = $surinfo["coach_id"];
        if ($coach_id) {
            $key = "getSurFdByCoachId:{$coach_id}";
            Base::redisSet($key, $surfd);
            devlog("监控或远控{$surimei}设置教练{$coach_id}");
        }
    }
}
